Python项目管理
虚拟环境
使用 pip 安装库,会被放到一个全局的环境中,被电脑上所有的 Python 项目共享,这种共享机制会带来如下两个问题
- 版本冲突:比如新项目需要 Flask 3.11,但电脑上某个旧项目可能只兼容 3.0 版
- 依赖地狱:即复杂的依赖关系,一个库通常依赖其它几个库,而这些库又有自己各自的依赖,这样层层嵌套,就会引发更多的版本冲突
虚拟环境就是为了解决这个问题被设计出来的。它可以为每个项目创建一个独立的 Python 工作空间,可以使用如下命令产生一个虚拟环境。
python -m venv .venv这里 .venv 就是给虚拟环境起的名字(可任取,但推荐这样),执行后项目里会产生一个名为 .venv 的目录,存放着一个独立的 Python 环境所需要的所有文件
如果没有使用 IDE (如PyCharm、VS Code、Jupyter Notebook 等) ,还需使用如下命令激活虚拟环境
source .venv/bin/activate激活虚拟环境之后,再使用 pip 安装之前的库,这一次 Flask 就会被安装到虚拟文件夹里了。这样,每个项目都可以拥有自己专属的虚拟文件夹,存放自己专属的依赖库,也就不会在产生冲突了。
虚拟环境起作用的原理,主要就是修改了 Python 中 sys. path 这个变量,
import sys,pprint
pprint.pp(sys.path)sys. path 是一个列表,记录了 Python 在导入模块时需要搜索的一系列文件夹路径,在执行 import 时,Python 会严格按照这个列表的顺序从头到尾检查这些路径,直到找到相应的包,在激活了虚拟环境之后,sys. path 会被修改,虚拟目录会被添加到这个搜索列表里.
隔离了项目之间的依赖,仍然有下面的问题:如何把项目的依赖列表方便准确地分享给别人?
一行一行执行一大堆 pip install 命令
使用 pip freeze 命令
pip freeze打印出当前虚拟环境中所有已经安装好的包,以及确切的版本号,用重定向符
pip freeze > requirements.txt 输出到 requirements. txt (可任取,但推荐这样),这样对方只需要执行
pip install -r requirements.txt pip 就会读取 requirements. txt 文件,并把里面的所有依赖全部安装一遍。
优点:直观 缺陷: pip freeze 分不清什么是我们项目真正需要的直接依赖,什么是这些依赖而引入的间接依赖。并且 pip 在卸载时也分不清这种依赖关系,比如当使用 pip uninstall 卸载 Flask时,pip 只会移除 Flask 本身,而那些因为他而被装上来的间接依赖全都留在了环境里面。
现代 Python 项目的标准解决方案是使用 pyproject. toml ,这是官方指定的统一配置文件,在此之前,不同的开发工具通常有各自独立的配置文件,比如
- 类型检查器 mypy 会使用 mypy. ini
- 测试框架 pytest 则使用 pytest. ini 当项目中使用的工具增多时,根目录下就会出现大量零散的配置文件,如今 Python 生态中绝大多数工具都支持了 pyproject. toml 文件,这样开发者就只需要维护这一个配置文件。
如果想用 pyproject. toml 替换 requirements ,只需要在 pyproject. toml 文件里添加一个 dependencies 的列表,关键区别在于声明项目直接依赖的包就可以了。比如
[project]
name = "proj"
version = "0.1.0"
dependencies = {
"Flask==3.1.1"
}然后 requirements 文件就可以被删掉了,若未来需要删除 Flask 3.1.1 依赖,只需要在 pyproject. toml 中删除对应行即可,依赖写好之后,在根目录下执行
pip install .安装依赖,这里的‘.’表示当前目录,这条命令会做两件事:
- 将当前项目打包为一个标准的 Python 软件包
- 安装刚刚打包好的软件包,并自动把所有声明的依赖一并安装进来
但是也带来新问题: 检查虚拟环境中 site-packages 目录时,会发现自己写的. py 文件也会被安装进去,这样项目里面就有了两份一模一样的源代码,在开发阶段很麻烦:
如果我们修改了源代码,这个改动并不会自动同步到虚拟环境中,为解决这个问题,只需在安装时加上一个 -e 参数,
pip install -e .这样 pip 安装时就不会把源代码复制到 site-packages 目录了,它会在这个目录下创建一个连接文件,当 python 要 import 项目代码时,他会顺着链接直接找到我们正在编辑的那个文件,确保我们的所有修改能够立刻生效。
以上纯手工方案很麻烦,社区中有 Poetry, UV, PDM 等解决方案,可以理解为是对 venv, pip 的高级封装。使用 uv 只需要一条简单的命令
uv add flask就能完成所有的事情:
- 自动修改 pyproject. toml 文件:把 flask 添加到 dependencies 列表里面
- 检查并自动创建 .venv 虚拟环境
- 把这个包和他所有的间接依赖安装到虚拟环境中 如果是项目协作者,只需要执行
uv sync uv 就会自动读取 pyproject. toml 文件,搭建好虚拟环境,并安装好所有的依赖,使用 uv 管理项目后,依然可以用传统命令运行代码,使用 source 命令激活虚拟环境,然后运行 python 文件;
python main.py同时 uv 提供了更加直接的做法
uv run main.py作用是在虚拟环境的上下文中执行命令,不需要手动激活环境,uv 会自动找到对应的 venv 在其中执行命名,然后再退出来。
使用 uv 管理
安装 uv
使用 uv 可以完成 Python 安装-> 虚拟环境 -> 依赖管理 -> 工具安装 -> 打包发布完整流程
使用如下命令安装 uv 并添加到系统路径 Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
macOS and Linux
curl -LsSf https://astral.sh/uv/install.sh | sh创建虚拟环境
uv venv在添加库时会自动创建虚拟环境
python 版本管理:
打印出 uv 支持的所有 Python 版本
uv python list 安装特定版本的 Python
uv python install 想要安装的版本使用特定版本的 Python 临时运行一个文件
uv run -p 版本号 脚本名称如果想要在交互的页面中使用
uv run -p 版本号 python其实在使用 uv run 之前并不需要特意的执行 uv python install ,在使用指定 python 版本时,如 uv run -p 版本号 python,如果之前没有安装过该版本 python,uv 就会在这时开始安装。
要使用jupyter需要添加ipykernel
项目依赖问题
创建 uv 工程
uv init -p python版本号此时 uv 会创建一系列的文件,
- hello. py : uv 生成的示例代码,没有什么用,可以删除
- .python-version: 记录了 python 的版本信息,如果想要换版本,可以在这里直接修改
- main. py: 这是之前我们写好的源代码,在 IDE 也许会提示它找不到~库,这时可以使用如下命令把这个库安装到当前工程中 添加库依赖
uv add 库的名称或者从 requirements. txt 转化
uv add -r requirements.txt这时 uv 不仅会下载库文件,还会自动为工程创建一个虚拟环境;可以点击 vscode 中 python 版本号来调整 vscode 使用的 python 解释器,使用我们的虚拟环境。我们所安装的工程依赖会被记录在 pyproject. toml 文件中
如果想知道工程所有库之间的依赖关系,可以使用如下命令打印出整个依赖树
uv tree 现在想要使用 ruff 工具检查代码是否符合规范,检查是否安装
ruff check 方法一:当作依赖直接引用进来
uv add ruff --dev加入 dev 参数是为了避免打包时把 ruff 也一起打包进来;但本质上它是一个工具,和代码是不相关的,而–dev 依赖应该还是放的与代码有关的,比如单元测试用到的 pytest 或者 mock 等 方法二:把想要安装的工具直接安装到系统之中。
uv tool install ruff此时的 ruff 就是脱离当前工程独立运行的了。
which ruff可以看到路径非当前虚拟环境。 使用 uv tool install 安装,整个系统都可以用,并且会为每个工具建立自己的虚拟环境,所以也不必担心库之间的冲突。 查看当前已经安装的工具
uv tool list 程序开发完成后,希望把它打包成一个可以直接运行的脚本,在 pyproject. toml 文件中,加入
[project.scripts]
脚本名称 = '想要运行的python脚本:函数名'比如 ai. py 中有 main ()
[project.scripts]
脚本名称 = 'ai:main'然后使用如下命令把整个工程打包为 whl 文件
uv build其它人就可以安装(用上面介绍的方法)和使用该脚本了
uv tool install 文件.whl 现在就可以直接使用 ai 命令了